#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/sched/signal.h>
#include <linux/string.h>
#include <linux/printk.h>
#include <linux/spinlock.h>

MODULE_LICENSE("GPL");

MODULE_AUTHOR("LuoWeiheng");

MODULE_DESCRIPTION("A simple kernel module with a list and two threads.");

MODULE_VERSION("1.0");

static struct list_head my_list;
static struct task_struct *thread1, *thread2;
spinlock_t lock;

// 定义链表节点结构
typedef struct pid_node
{
    int pid;
    char comm[16];
    struct list_head list;
}node;

// thread1 函数体
static int thread1_func(void *data)
{
    pr_info("thread1 start\n");
    pr_info("thread1 parent pid:%d, comm:%s", current->parent->pid, current->parent->comm);
    // 开始创建内核数据链表
    // 1. 遍历内核进程链表
    struct task_struct *task = NULL;
    rcu_read_lock();
    for_each_process(task) {
        // 2. 遍历内核进程链表，并创建自己的内核数据链表
        node *tmp = (node*)kmalloc(sizeof(node), GFP_KERNEL | __GFP_ZERO);
        if (!tmp) {
            pr_err("failed to kmalloc\n");
            break;
        }
        // 更新数据
        tmp->pid = task->pid;
        strncpy(tmp->comm, task->comm, 15);
        tmp->comm[15] = '\0';
        // 将新创建的节点加入内核数据链表中
        // 往内核数据链表中加载时，需要自旋锁
        spin_lock(&lock);
        list_add_tail(&tmp->list, &my_list);
        spin_unlock(&lock);
        // 如果收到线程停止信号，就停止遍历进程链表
        if(kthread_should_stop()) {
            break;
        }
    }
    rcu_read_unlock();
    while (!kthread_should_stop()) {
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(msecs_to_jiffies(1000));
    }
    pr_info("thread1 end\n");
    return 0;
}
// thread2 函数体
static int thread2_func(void *data)
{
    pr_info("thread2 start\n");
    pr_info("thread2 parent pid:%d, comm:%s", current->parent->pid, current->parent->comm);
    node* entry = NULL;
    // 首先需要不断扫描内核数据链表, 如果没有收到线程停止信号
    while (!kthread_should_stop()) {
        spin_lock(&lock);
        // 判断链表是否为空，如果是空，什么都不做
        if (!list_empty(&my_list)) {
            // 链表非空，尝试获得一个数据节点
            entry = list_first_entry(&my_list, node, list);
            // 在数据链表中删除当前节点
            list_del(&entry->list);
        }
        spin_unlock(&lock);
        // 打印数据并释放资源
        if (entry) {
            pr_info("pid :%-10d\tname:%s\n", entry->pid, entry->comm);
            kfree(entry);
            entry = NULL;
        }
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(msecs_to_jiffies(10));
    }
    pr_info("thread2 end\n");
    return 0;
}

// 模块初始化函数
static int __init kernel_module_init(void)
{
    printk(KERN_INFO "List and thread module init\n");
    // 初始化内核链表头
    INIT_LIST_HEAD(&my_list);
    // 初始化自旋锁
    spin_lock_init(&lock);
    // 创建线程1
    printk(KERN_INFO "creating thread1\n");
    thread1 = kthread_create(thread1_func, NULL, "thread1");
    if (IS_ERR(thread1)) {
        pr_err("failed to create thread1, error code: %ld\n", PTR_ERR(thread1));
        return PTR_ERR(thread1);
    }
    pr_info("creating thread1 successfully\n");
    wake_up_process(thread1);
    pr_info("creating thread2\n");
    thread2 = kthread_run(thread2_func, NULL, "thread2");
    if (IS_ERR(thread2)) {
        pr_err("failed to create thread2, error code: %ld\n", PTR_ERR(thread2));
        return PTR_ERR(thread2);
    }
    pr_info("creating and run thread2 successfully\n");

    return 0;
}


// 模块清理函数
static void __exit kernel_module_exit(void)
{
    pr_info("List and thread module is exiting\n");
   //TODO: add code here
    // 停止线程1
    if (thread1 && !IS_ERR(thread1)) {
        int ret = kthread_stop(thread1);
        pr_info("thread1 has exited with code : %d\n", ret);
        thread1 = NULL;
    }
    // 停止线程2
    if (thread2 && !IS_ERR(thread2)) {
        int ret = kthread_stop(thread2);
        pr_info("thread2 has exited with code : %d\n", ret);
        thread2 = NULL;
    }
    node *entry = NULL;
    node *nentry = NULL;
    // 清理链表
    pr_info("delete list\n");
    pr_info("remaining node information:\n");
    list_for_each_entry_safe(entry, nentry, &my_list, list) {
        // 打印剩下的节点信息
        pr_info("pid :%-10d\tname:%s\n", entry->pid, entry->comm);
        // 删除链表节点
        list_del(&entry->list);
        // 释放申请的内存
        kfree(entry);
    }

    printk(KERN_INFO "List and thread module exit\n");
}

module_init(kernel_module_init);

module_exit(kernel_module_exit);
